package cn.openea.perpartner.meily.web.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.openea.perpartner.common.core.utils.DateUtils;
import cn.openea.perpartner.meily.rabbit.domain.DelayDto;
import cn.openea.perpartner.meily.rabbit.factory.DelayServiceFactory;
import cn.openea.perpartner.meily.rabbit.service.DelayService;
import cn.openea.perpartner.meily.web.entity.Goods;
import cn.openea.perpartner.meily.web.entity.GroupBuying;
import cn.openea.perpartner.meily.web.entity.GroupBuyingSub;
import cn.openea.perpartner.meily.web.mapper.SettlementIncomeMapper;
import cn.openea.perpartner.meily.web.service.IGoodsService;
import cn.openea.perpartner.meily.web.service.IGroupBuyingSubService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;

/**
 * @author rains
 * @since 2023-02-17 11:34
 */
@Slf4j
@Service("settlementIncomeService")
public class SettlementIncomeServiceImpl extends ServiceImpl<SettlementIncomeMapper, GroupBuying> implements DelayService {

    @Value("${bpm.rest.url}")
    private String bpmUrl;
    @Value("${meily.header.sysid}")
    private String sysId;
    @Value("${meily.header.syspwd}")
    private String sysPwd;
    @Value("${bpm.msg_appid}")
    private String msgAppid;
    @Value("${bpm.msg_wf_num}")
    private String msgWfNum;
    @Value("${payment.order.authSalt}")
    private String authSalt;
    @Value("${payment.order.getTokenUrl}")
    private String getOrderSysTokenUrl;
    @Value("${payment.order.subPayToWallet}")
    private String subPayToWallet;
    @Value("${integral_sysytem_id}")
    private String INTEGRAL_SYSTEM_ID;

    @Autowired
    private IGroupBuyingSubService groupBuyingSubService;

    @Autowired
    private IGoodsService goodsService;
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    @Override
    public TimerTask execute(DelayDto delay) {
        return new TimerTask() {
            @Override
            public void run() {
                try{
                    // 具体业务实现函数
                    // settlement(delay.getGoodsId(), delay.getCyclicId());
                    log.info("暂不使用MQ自动结算。");
                } catch (Exception e){
                    log.error("结算失败，失败原因："+e.getMessage());
                }
            }
        };
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        DelayServiceFactory.register("settlementIncomeService",this);
    }


    /**
     * 结算
     * 步骤：
     *  1.获取商品销量大于100的拼团记录（拼团未结束）；
     *  2.结束拼团(即修改状态status = "2")；
     *  3.结算：发放团销利润、通知；
     *      3-1.给消费者发放团销报酬、通知
     *      3-2.给线上服务商(团长)发放团销报酬、通知
     *  4.给区域服务商发放通知。
     *  5.结算直接购买商品（即团长是平台）。---暂时不用处理此情况
     * @param goodsId 商品id
     * @param cyclicId 周期串
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public boolean settlement(String goodsId, String cyclicId) throws Exception {

        log.info("开始执行结算......");
        log.info("********************");

        /**
         * 获取结算需要的信息
         */
        // 1.商品信息
        Goods goods = goodsService.getById(goodsId);
        if(BeanUtil.isEmpty(goods)){
            log.error("根据商品id（"+goodsId+"）获取不到商品信息，无法进行结算！");
            log.info("执行结束（出错中断）。");
            log.info("********************************");
            return false;
        }

        // 2.商品自定义销量
        long customSales = 0;
        if(StrUtil.isNotBlank(goods.getCustomSales())){
            customSales = Long.parseLong(goods.getCustomSales());
        }

        /**
         * 第1步 获取商品销量大于100的拼团记录（拼团未结束）
         */
        List<GroupBuying> list = getGroupBuyingList(goodsId, cyclicId, customSales);
        // 遍历查询到的拼团记录
        for(GroupBuying gb : list){

            // 3.商品实际销量(本期累计的商品销量)
            long actualSales = groupBuyingSubService.getTotalBuyQuantity(gb.getGoodsId(), gb.getCycle(), "");

            // 4.商品总销量 = 商品实际销量 + 商品自定义销量
            long totalSales = actualSales + customSales;

            // 商品销量未达标则，则进入下一循环
            if(totalSales < 100){
                log.info("此拼团("+gb.getId()+")的商品总销量未达到标准，无需要发放团销返利！");
                continue;
            }

            String consumerCashback = "";// 消费者返现金额
            String onlineCashback = "";// 线上服务商返利金额
            String groupType = "";// 团购类型。百人团/千人团/万人团

            if(totalSales > 100 && totalSales <= 1000){
                // 百人团
                consumerCashback = goods.getHundredConsumerCashback();
                onlineCashback = goods.getHundredOnlineCashback();
                groupType = "百人团";

            } else if(totalSales > 1000 && totalSales <= 10000){
                // 千人团
                consumerCashback = goods.getThousandConsumerCashback();
                onlineCashback = goods.getThousandOnlineCashback();
                groupType = "千人团";

            } else if(totalSales > 10000){
                // 万人团
                consumerCashback = goods.getTenThousandConsumerCashback();
                onlineCashback = goods.getTenThousandOnlineCashback();
                groupType = "万人团";
            }

            JSONObject basicInfoObject = new JSONObject();
            basicInfoObject.put("customSales", customSales);// 商品自定义销量
            basicInfoObject.put("actualSales", actualSales);// 商品实际销量
            basicInfoObject.put("totalSales", totalSales);// 商品总销量
            basicInfoObject.put("consumerCashback", consumerCashback);// 消费者返现金额
            basicInfoObject.put("onlineCashback", onlineCashback);// 线上服务商返利金额
            basicInfoObject.put("groupType", groupType);// 团购类型。百人团/千人团/万人团

            /**
             * 第2步 结束拼团(即修改状态status = "2")
             */
            if(!endGroup(gb.getId())){
                log.error("结束拼团修改状态出错了，出错记录：" + gb.getId());
                return false;
            }

            /**
             * 第3步 结算：发放团销利润、通知
             */
            if(!settlementGroup(gb, basicInfoObject)){
                log.error("拼团("+gb.getId()+")发放团销利润、通知出错了！");
                return false;
            }
        }

        /**
         * 第4步 给区域服务商发送结算通知
         */
        if(!sendMsgToProvider(goodsId, cyclicId, goods)){
            log.error("给区域服务商发送结算通知出错了！");
            return false;
        }

        /**
         * 第5步 结算直接购买商品（即团长是平台）；---暂时不用处理此情况

        if(!settlementByPlatform(goodsId, cyclicId, goods)){
            log.error("结算直接购买商品出错了！");
            return false;
        }*/

        log.info("********************");
        log.info("执行结束。");
        return true;
    }

    /**
     * 第1步 获取商品销量大于100的拼团记录（拼团未结束）
     * @param goodsId 商品id
     * @param cyclicId 周期串
     * @param customSales 商品自定义销量
     * @return
     */
    public List<GroupBuying> getGroupBuyingList(String goodsId, String cyclicId, long customSales){
        // 参与拼团记录表meily_group_buying_sub中的main_docunid!=goods_id
        QueryWrapper<GroupBuying> queryWrapper = new QueryWrapper<GroupBuying>();
        // queryWrapper.select("main_docunid");
        queryWrapper.eq("goods_id", goodsId);
        queryWrapper.eq("cycle", cyclicId);

        // 拼团主文档id 不等于 商品id，表示此拼团是由线上服务商发起的
        queryWrapper.ne("main_docunid", goodsId);

        queryWrapper.groupBy("main_docunid");
        queryWrapper.having(" sum(buy_quantity) >= " + (100-customSales));
        return baseMapper.getlist(queryWrapper);
    }

    /**
     * 第2步 结束拼团(即修改状态status = "2")
     * @param id 拼团记录id
     *  @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public boolean endGroup(String id) throws Exception {

        LambdaUpdateWrapper<GroupBuying> updateWrapper = new LambdaUpdateWrapper<GroupBuying>();
        updateWrapper.eq(GroupBuying::getId, id);
        updateWrapper.eq(GroupBuying::getStatus, "1");// 状态。0:废弃；1:启用；2:结束；
        // 修改拼团状态为：结束
        updateWrapper.set(GroupBuying::getStatus, "2");// 状态
        updateWrapper.set(GroupBuying::getFinishTime, DateUtils.getNow());// 拼团时间结束时间
        updateWrapper.set(GroupBuying::getUpdateTime, DateUtils.getNow());// 更新时间

        return update(updateWrapper);
    }

    /**
     * 第3步 结算：发放团销利润、通知
     * 步骤：
     *  1.根据拼团主文档id获取所有参与团购记录；
     *  2.给消费者发放团销返利与通知；
     *  3.给线上服务商发放团销返利与通知
     * @param gb 拼团详情
     * @param basicInfoObject 结算需要的基本信息
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public boolean settlementGroup(GroupBuying gb, JSONObject basicInfoObject){

        // 1.根据拼团主文档id获取所有参与团购记录
        List<GroupBuyingSub> allJoinList = groupBuyingSubService.getAllJoinList(gb.getId());

        if(allJoinList.size() < 0){
            log.info("根据拼团id("+gb.getId()+")获取不到参与记录，无需要进行结算！");
            return true;
        }

        // 2.给消费者发放团销返利与通知
        if(StrUtil.isNotBlank(basicInfoObject.getString("consumerCashback")) && basicInfoObject.getDouble("consumerCashback") > 0){
            // 遍历所有参与团购记录
            for (GroupBuyingSub gbSub : allJoinList) {

                // 消费者团销返利总额 = 消费者团销返利 * 消费者自己购买数量 * 100.0
                double _reward = basicInfoObject.getDouble("consumerCashback") * Double.parseDouble(gbSub.getBuyQuantity());

                // 需要增加的积分 = 消费者团销返利总额 * 100.0
                double points = _reward * 100.0;

                /**
                 * 情况1：在团购结束之前已确认收货的消费者
                 *  1.发放消费者团销返利；
                 *  2.发送通知。
                 */
                if("已完成".equals(gbSub.getOrderStatus())){
                    // 1.发放消费者团销返利；
                    // 调用积分系统：转入钱包
                    JSONObject object = new JSONObject();
                    object.put("userId", gbSub.getPartnerId());// 消费者id
                    object.put("points", String.format("%.0f", points));// 保留0位小数
                    object.put("reason", gbSub.getGoodsName() +"团购团销返利，共" + String.format("%.2f", _reward) + "元");
                    object.put("sceneId", INTEGRAL_SYSTEM_ID);// 自定义积分体系 ID
                    object = getToken(object);
                    String result = subPayToWallet(object);
                    String code = JSON.parseObject(result).getString("code");
                    if(!"200".equals(code)){
                        log.error("给已确认收货的消费者发放团销返利失败！");
                        return false;
                    }

                    // 2.发送通知。
                    HashMap<String, Object> params = new HashMap<>();
                    // params.put("first", gbSub.getGoodsName() + "团购活动已结束，累计销量" + basicInfoObject.getLong("totalSales")  + "件，已达到品牌" + basicInfoObject.getString("groupType") + "返现标准。您参与购买" + gbSub.getBuyQuantity() + "件商品，获返现" + String.format("%.2f", _reward) + "元。");
                    params.put("first", "亲，本场活动已结束，活动累计总销量" + basicInfoObject.getLong("totalSales")  + "件，已成" + basicInfoObject.getString("groupType") + "。您参与购买" + gbSub.getBuyQuantity() + "件商品，获返现" + String.format("%.2f", _reward) + "元。");
                    params.put("keyword1", gbSub.getTaskNumber());// 订单编号
                    params.put("keyword2", gbSub.getGoodsName());// 商品名称
                    params.put("remark", "点击查看收益详情。平台现有大量零食/美妆/洗护/母婴/百货等商品销售资源，佣金非常可观，欢迎前往选品！");
                    params.put("pagepath", "/pages/index/incomeIndex");// （链接到【收益页面】）
                    params.put("pageurl", "/pages/index/incomeIndex");// （链接到【收益页面】）
                    params.put("docUnid", gbSub.getId());
                    params.put("userId", gbSub.getPartnerId());
                    JSONObject obj = sendMsg(params);
                    if(!"200".equals(obj.getString("code"))){
                        log.error("给已确认收货的消费者发送通知失败！");
                        return false;
                    }
                }

                /**
                 * 情况2：在团购结束之前已发货，但未确认收货的消费者
                 *  1.发送通知。
                 */
                if("已发货".equals(gbSub.getOrderStatus())){
                    // 1.发送通知。
                    HashMap<String, Object> params = new HashMap<>();
                    // params.put("first", gbSub.getGoodsName() + "团购活动已结束，累计销量" + basicInfoObject.getLong("totalSales") + "件，已达到品牌" + basicInfoObject.getString("groupType") + "返现标准。您参与购买" + gbSub.getBuyQuantity() + "件商品，预计返现" + String.format("%.2f", _reward) + "元，确认收货后立即返现！");
                    params.put("first", "亲，本场活动已结束，活动累计总销量" + basicInfoObject.getLong("totalSales") + "件，已成" + basicInfoObject.getString("groupType") + "。您参与购买" + gbSub.getBuyQuantity() + "件商品，预计返现" + String.format("%.2f", _reward) + "元，确认收货后立即返现！");
                    params.put("keyword1", gbSub.getTaskNumber());// 订单编号
                    params.put("keyword2", gbSub.getGoodsName());// 商品名称
                    params.put("remark", "点击查看订单详情。平台现有大量零食/美妆/洗护/母婴/百货等商品销售资源，佣金非常可观，欢迎前往选品！");
                    params.put("pagepath", "/pages_private_scene2/GroupPurchase/OrderDetails?recordId="+gbSub.getId()+"&scenario=2");// （链接到【订单详情】）
                    params.put("pageurl", "/pages_private_scene2/GroupPurchase/OrderDetails?recordId="+gbSub.getId()+"&scenario=2");// （链接到【订单详情】）
                    params.put("docUnid", gbSub.getId());
                    params.put("userId", gbSub.getPartnerId());
                    JSONObject obj = sendMsg(params);
                    if(!"200".equals(obj.getString("code"))){
                        log.error("给已发货但未确认收货的消费者发送通知失败！");
                        return false;
                    }
                }

                /**
                 * 情况3：在团购结束之前已下单但平台还没有发货的消费者
                 *  1.发送通知。
                 */
                if("已付款".equals(gbSub.getOrderStatus())){
                    // 1.发送通知。
                    HashMap<String, Object> params = new HashMap<>();
                    // params.put("first", gbSub.getGoodsName() + "团购活动已结束，累计销量" + basicInfoObject.getLong("totalSales") + "件，已达到品牌" + basicInfoObject.getString("groupType") + "返现标准。您参与购买" + gbSub.getBuyQuantity() + "件商品，预计返现" + String.format("%.2f", _reward) + "元！目前订单较多，请您耐心等待物流通知，确认收货后立即返现！");
                    params.put("first", "亲，本场活动已结束，活动累计总销量" + basicInfoObject.getLong("totalSales") + "件，已成" + basicInfoObject.getString("groupType") + "返现标准。您参与购买" + gbSub.getBuyQuantity() + "件商品，预计返现" + String.format("%.2f", _reward) + "元！目前订单较多，请您耐心等待物流通知，确认收货后立即返现！");
                    params.put("keyword1", gbSub.getTaskNumber());// 订单编号
                    params.put("keyword2", gbSub.getGoodsName());// 商品名称
                    params.put("remark", "点击查看订单详情。平台现有大量零食/美妆/洗护/母婴/百货等商品销售资源，佣金非常可观，欢迎前往选品！");
                    params.put("pagepath", "/pages_private_scene2/GroupPurchase/OrderDetails?recordId="+gbSub.getId()+"&scenario=3");// （链接到【订单详情】）
                    params.put("pageurl", "/pages_private_scene2/GroupPurchase/OrderDetails?recordId="+gbSub.getId()+"&scenario=3");// （链接到【订单详情】）
                    params.put("docUnid", gbSub.getId());
                    params.put("userId", gbSub.getPartnerId());

                    JSONObject obj = sendMsg(params);
                    if(!"200".equals(obj.getString("code"))){
                        log.error("给已付款但发货的消费者发送通知失败！");
                        return false;
                    }
                }
            }
        } else {
            log.info("【消费者返现金额("+basicInfoObject.getDouble("consumerCashback")+")】小于零或为空，无需要进行结算！");
            return true;
        }

        // 3.给线上服务商发放团销返利与通知
        if(StrUtil.isNotBlank(basicInfoObject.getString("onlineCashback")) && basicInfoObject.getDouble("onlineCashback") > 0){

            int completedOrderQuantity = 0;// 已完成订单数量
            long completedGoodsQuantity = 0;// 已完成订单的商品数量

            int qutstandingOrderQuantity = 0;// 未完成订单数量
            long qutstandingGoodsQuantity = 0;// 未完成订单的商品数量

            long totalOrderQuantity = 0;// 所有订单数量
            long totalGoodsQuantity = 0;// 所有订单的商品数量
            double totalSales = 0.0;// 销售总额

            // 遍历所有参与团购记录，统计订单是否全部已完成
            for (GroupBuyingSub gbSub : allJoinList) {

                if("已完成".equals(gbSub.getOrderStatus())){
                    completedOrderQuantity++;
                    completedGoodsQuantity += Long.parseLong(gbSub.getBuyQuantity());

                } else {
                    qutstandingOrderQuantity++;
                    qutstandingGoodsQuantity += Long.parseLong(gbSub.getBuyQuantity());
                }
                totalOrderQuantity++;
                totalGoodsQuantity += Long.parseLong(gbSub.getBuyQuantity());
                totalSales += Double.parseDouble(gbSub.getPayAmount());
            }

            // 线上服务商团销返利总额 = 线上服务商团销返利 * 此拼团【所有的】订单的商品购买数量
            double totalReward = basicInfoObject.getDouble("onlineCashback") * totalOrderQuantity;

            // 需要增加的积分 = 线上服务商团销返利总额 * 100.0
            double totalPoints =  totalReward * 100.0;

            /**
             * 情况1：团购结束后，全部订单已完成的情况
             *  1.发放线上服务商团销返利（全部的返现）；
             *  2.发送通知。
             */
            if(qutstandingOrderQuantity == 0){
                // 1.发放线上服务商团销返利
                JSONObject object = new JSONObject();
                object.put("userId", gb.getInitiatorId());// 线上服务商
                object.put("points", String.format("%.0f", totalPoints));// 保留0位小数
                object.put("reason", gb.getGoodsName() +"团购团销返利，共" + String.format("%.2f", totalReward) + "元");
                object.put("sceneId", INTEGRAL_SYSTEM_ID);// 自定义积分体系 ID
                object = getToken(object);
                String result = subPayToWallet(object);
                String code = JSON.parseObject(result).getString("code");
                if(!"200".equals(code)){
                    log.error("全部订单已完成的情况:给线上服务商发放团销返利失败！");
                    return false;
                }

                // 2.发送通知。
                HashMap<String, Object> params = new HashMap<>();
                // params.put("first", "【线上服务商】" + gb.getGoodsName() + "团购活动已结束，累计销量" + basicInfoObject.getLong("totalSales") + "件，已达到品牌" + basicInfoObject.getString("groupType") + "返现标准。您已售出" +totalGoodsQuantity + "件商品，销售总额" + String.format("%.2f", totalSales) + "元，品牌返利" + String.format("%.2f", totalReward) + "元！");
                params.put("first", "【线上服务商】亲，本场活动已结束，活动累计总销量" + basicInfoObject.getLong("totalSales") + "件，已成" + basicInfoObject.getString("groupType") + "。您已售出" +totalGoodsQuantity + "件商品，销售总额" + String.format("%.2f", totalSales) + "元，本次返利" + String.format("%.2f", totalReward) + "元！");
                params.put("keyword1", gb.getTaskNumber());// 订单编号
                params.put("keyword2", gb.getGoodsName());// 商品名称
                params.put("remark", "共完成有"+completedOrderQuantity+"个团购订单，点击查看收益详情。平台现有大量零食/美妆/洗护/母婴/百货等商品销售资源，佣金非常可观，欢迎前往选品！");
                params.put("pagepath", "/pages/index/incomeIndex");// （链接到【收益页面】）
                params.put("pageurl", "/pages/index/incomeIndex");// （链接到【收益页面】）
                params.put("docUnid", gb.getId());
                params.put("userId", gb.getInitiatorId());
                JSONObject obj = sendMsg(params);
                if(!"200".equals(obj.getString("code"))){
                    log.error("全部订单已完成的情况:给线上服务商发送通知失败！");
                    return false;
                }
            } else {
                /**
                 * 情况2：团购结束后，部分订单未完成的情况
                 *  1.发放线上服务商团销返利（部分的返现）；
                 *  2.发送通知。
                 */
                // 线上服务商团销返利总额 = 线上服务商团销返利 * 此拼团【已完成的】订单的商品购买数量
                double _reward = basicInfoObject.getDouble("onlineCashback") * completedGoodsQuantity;

                // 需要增加的积分 = 线上服务商团销返利总额 * 100.0
                double points =  _reward * 100.0;

                // 1.发放线上服务商团销返利
                JSONObject object = new JSONObject();
                object.put("userId", gb.getInitiatorId());// 线上服务商
                object.put("points", String.format("%.0f", points));// 保留0位小数
                object.put("reason", gb.getGoodsName() +"团购团销返利，共" + String.format("%.2f", _reward) + "元");
                object.put("sceneId", INTEGRAL_SYSTEM_ID);// 自定义积分体系 ID
                object = getToken(object);
                String result = subPayToWallet(object);
                String code = JSON.parseObject(result).getString("code");
                if(!"200".equals(code)){
                    log.error("部分订单未完成的情况:给线上服务商发放团销返利失败！");
                    return false;
                }
                // 2.发送通知。
                HashMap<String, Object> params = new HashMap<>();
                // params.put("first", "【线上服务商】" + gb.getGoodsName() + "团购活动已结束，累计销量" + basicInfoObject.getLong("totalSales") + "件，已达到品牌" + basicInfoObject.getString("groupType") + "返现标准。您已售出" +completedGoodsQuantity + "件商品，销售总额" + String.format("%.2f", totalSales) + "元，品牌返利" + String.format("%.2f", totalReward) + "元！");
                params.put("first", "【线上服务商】亲，本场活动已结束，活动累计总销量" + basicInfoObject.getLong("totalSales") + "件，已成" + basicInfoObject.getString("groupType") + "。您已售出" +totalGoodsQuantity + "件商品，销售总额" + String.format("%.2f", totalSales) + "元，本次返利" + String.format("%.2f", totalReward) + "元！");
                params.put("keyword1", gb.getTaskNumber());// 订单编号
                params.put("keyword2", gb.getGoodsName());// 商品名称
                params.put("remark", completedOrderQuantity+"个订单("+completedGoodsQuantity+"件商品)已签收，返利"+String.format("%.2f", totalReward)+"元，点击查看收益详情。仍有"+qutstandingOrderQuantity+"个订单（"+qutstandingGoodsQuantity+"件商品）未签收！平台现有大量零食/美妆/洗护/母婴/百货等商品销售资源，佣金非常可观，欢迎前往选品！");
                params.put("pagepath", "/pages/index/incomeIndex");// （链接到【收益页面】）
                params.put("pageurl", "/pages/index/incomeIndex");// （链接到【收益页面】）
                params.put("docUnid", gb.getId());
                params.put("userId", gb.getInitiatorId());
                JSONObject obj = sendMsg(params);
                if(!"200".equals(obj.getString("code"))){
                    log.error("部分订单未完成的情况:给线上服务商发送通知失败！");
                    return false;
                }
            }
        } else {
            log.info("【线上服务商金额("+basicInfoObject.getDouble("onlineCashback")+")】小于零或为空，无需要进行结算！");
            return true;
        }

        log.info("结算拼团("+gb.getId()+")执行成功！");
        return true;

    }

    /**
     * 第4步 给区域服务商发放通知
     * @param goodsId 商品id
     * @param cyclicId 周期串
     * @param goods 商品实例对象
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public boolean sendMsgToProvider(String goodsId, String cyclicId, Goods goods){

        // 1.自定义销量
        long customSales = 0;
        if(StrUtil.isNotBlank(goods.getCustomSales())){
            customSales = Long.parseLong(goods.getCustomSales());
        }

        // 2.获取当前周期商品实际销量
        long totalBuyQuantity = groupBuyingSubService.getTotalBuyQuantity(goodsId, cyclicId, "");

        totalBuyQuantity = totalBuyQuantity + customSales;

        if(totalBuyQuantity < 100){
            log.info("【"+goods.getGoodsName()+"("+goods.getGoodsId()+"）】销量未达到标准，无需要给区域服务商发放通知！");
            return true;
        }

        String providerCashback = "";// 区域服务商返现金额
        String groupType = "";// 团购类型。百人团/千人团/万人团
        if(totalBuyQuantity > 100 && totalBuyQuantity <= 1000){
            providerCashback = goods.getHundredProviderCashback();
            groupType = "百人团";
        } else if(totalBuyQuantity > 1000 && totalBuyQuantity <= 10000){
            providerCashback = goods.getThousandProviderCashback();
            groupType = "千人团";
        } else if(totalBuyQuantity > 10000){
            providerCashback = goods.getTenThousandProviderCashback();
            groupType = "万人团";
        }

        if(StrUtil.isNotBlank(providerCashback) && Double.parseDouble(providerCashback) > 0){
            // 获取当前周期下某商品的所有购买记录
            List<GroupBuyingSub> allBuyingList = groupBuyingSubService.getAllBuyingList(goodsId, cyclicId);

            // 存储每个区域服务商的订单数量、商品销量、奖励
            Map<String,Object> map = new HashMap<String,Object>();

            // 遍历所有购买记录
            for (GroupBuyingSub gbSub : allBuyingList) {

                String supplierId = gbSub.getSupplierId();// 区域服务商id

                // 获取区域商信息
                JSONObject supplierObject = JSONObject.parseObject(gbSub.getSupplier());
                String providerId = "";
                if(StrUtil.isNotBlank(supplierObject.getString("providerId"))){
                    providerId = "N0." + supplierObject.getString("providerId");
                }

                // 判断key是否存在
                if(map.containsKey(supplierId)){
                    // 存在，则重新计算object
                    JSONObject object = (JSONObject)map.get(supplierId);
                    object.put("orderNum", object.getLong("orderNum") + 1);// 订单数量 + 1
                    object.put("goodsNum", object.getLong("goodsNum") + Long.parseLong(gbSub.getBuyQuantity()));// 商品销量
                    object.put("reward", object.getDouble("reward") + (Double.parseDouble(providerCashback) * Long.parseLong(gbSub.getBuyQuantity())));// 奖励
                    object.put("providerId", providerId);// 区域服务商编号
                    map.put(supplierId, object);

                } else {
                    JSONObject object = new JSONObject();
                    object.put("orderNum", 1);// 订单数量
                    object.put("goodsNum", Long.parseLong(gbSub.getBuyQuantity()));// 商品销量
                    object.put("reward", Double.parseDouble(providerCashback) * Long.parseLong(gbSub.getBuyQuantity()));// 奖励
                    object.put("providerId", providerId);// 区域服务商编号
                    map.put(supplierId, object);
                }
            }

            // 遍历map对象
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                String supplierId = entry.getKey();
                // JSONObject object = (JSONObject) JSONObject.toJSON(entry.getValue());
                JSONObject object = JSON.parseObject(JSON.toJSONString(entry.getValue()), JSONObject.class);

                // 给区域服务商发送通知。
                HashMap<String, Object> params = new HashMap<>();
                // params.put("first", "【区域服务商" + object.getString("providerId") + "】" + goods.getGoodsName() + "团购活动已结束，累计销量" + totalBuyQuantity + "件，已达到品牌" + groupType + "返现标准。您所在的区域产生" + object.getLong("orderNum") + "个订单，合计" + object.getLong("goodsNum") + "件商品，预计获得平台奖励" + String.format("%.2f", object.getDouble("reward")) + "元！");
                params.put("first", "【区域服务商" + object.getString("providerId") + "】亲，本场活动已结束，活动累计总销量" + totalBuyQuantity + "件，已成" + groupType + "。您所在的区域产生" + object.getLong("orderNum") + "个订单，合计" + object.getLong("goodsNum") + "件商品，预计获得平台奖励" + String.format("%.2f", object.getDouble("reward")) + "元！");
                params.put("keyword1", cyclicId);// 订单编号(周期串)
                params.put("keyword2", goods.getGoodsName());// 商品名称
                params.put("remark", "月底统一结算并发放奖励！您所在区域发现不少潜在消费者，建议您发起商品销售，平台现有大量零食/美妆/洗护/母婴/百货等商品销售资源，佣金非常可观，欢迎前往选品！");
                params.put("pagepath", "/pages/index/evaluationIndex");// （链接到【平台-生活】）
                params.put("pageurl", "/pages/index/evaluationIndex");// （链接到【平台-生活】）
                params.put("docUnid", "");
                params.put("userId", supplierId);

                JSONObject obj = sendMsg(params);
                if(!"200".equals(obj.getString("code"))){
                    log.error("给区域服务商（"+supplierId+"）发送通知失败！");
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 第5步 结算直接购买商品（即团长是平台）；
     * 步骤：
     *  5-1.给消费者发放团销报酬;
     *  5-2.给消费者发送团销通知。
     * @param goodsId 商品id
     * @param cyclicId 周期串
     * @param goods 商品实例对象
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public boolean settlementByPlatform(String goodsId, String cyclicId, Goods goods) throws Exception {

        // 1.商品自定义销量
        long customSales = 0;
        if(StrUtil.isNotBlank(goods.getCustomSales())){
            customSales = Long.parseLong(goods.getCustomSales());
        }

        // 2.获取直接购买商品实际销量
        long totalBuyQuantity = groupBuyingSubService.getTotalBuyQuantity(goodsId, cyclicId, goodsId);

        totalBuyQuantity = totalBuyQuantity + customSales;

        if(totalBuyQuantity < 100){
            log.info("商品销量总数未达到标准，无需要发放团销返利！");
            return true;
        }

        String consumerCashback = "";// 消费者返现金额
        String groupType = "";// 团购类型。百人团/千人团/万人团

        if(totalBuyQuantity > 100 && totalBuyQuantity <= 1000){
            // 百人团
            consumerCashback = goods.getHundredConsumerCashback();
            groupType = "百人团";

        } else if(totalBuyQuantity > 1000 && totalBuyQuantity <= 10000){
            // 千人团
            consumerCashback = goods.getThousandConsumerCashback();
            groupType = "千人团";

        } else if(totalBuyQuantity > 10000){
            // 万人团
            consumerCashback = goods.getTenThousandConsumerCashback();
            groupType = "万人团";
        }

        // 给消费者发放团销返利
        if(StrUtil.isNotBlank(consumerCashback) && Double.parseDouble(consumerCashback) > 0){
            List<GroupBuyingSub> list = groupBuyingSubService.getCompletedGroupRecordList(goodsId, cyclicId, goodsId);
            for (GroupBuyingSub gbSub : list) {

                // 消费者团销返利总额 = 消费者团销返利 * 消费者自己购买数量；
                double _reward = Double.parseDouble(consumerCashback) * Double.parseDouble(gbSub.getBuyQuantity());

                // 需要增加的积分 = 消费者团销返利总额 * 100.0
                double points = _reward * 100.0;

                // 调用积分系统：转入钱包
                JSONObject object = new JSONObject();
                object.put("userId", gbSub.getPartnerId());// 消费者id
                object.put("points", String.format("%.0f", points));// 保留0位小数
                object.put("reason", gbSub.getGoodsName() +"团购团销返利，共" + String.format("%.2f", _reward) + "元");
                object.put("sceneId", INTEGRAL_SYSTEM_ID);// 自定义积分体系 ID
                object = getToken(object);
                String result = subPayToWallet(object);
                String code = JSON.parseObject(result).getString("code");
                if(!"200".equals(code)){
                    log.error("给消费者发放团销返利失败！");
                    return false;
                }

                // 给消费者发送返现通知
                HashMap<String, Object> params = new HashMap<>();
                params.put("first", gbSub.getGoodsName() + "团购活动已结束，累计销量" + totalBuyQuantity + "件，已达到品牌" + groupType + "返现标准。您参与购买" + gbSub.getBuyQuantity() + "件商品，获返现" + String.format("%.2f", _reward) + "元。");
                params.put("keyword1", gbSub.getTaskNumber());// 订单编号
                params.put("keyword2", gbSub.getGoodsName());// 商品名称
                params.put("remark", "点击查看收益详情。");
                params.put("pagepath", "/pages/index/incomeIndex");// （链接到【收益页面】）
                params.put("pageurl", "/pages/index/incomeIndex");// （链接到【收益页面】）
                params.put("docUnid", gbSub.getId());
                params.put("userId", gbSub.getPartnerId());
                JSONObject obj = sendMsg(params);
                if(!"200".equals(obj.getString("code"))){
                    log.error("给消费者发送返现通知失败！");
                    return false;
                }
            }
        }
        log.info("给消费者发放团销返利成功！");
        return true;
    }

    /** ********************* 以下调用其他系统的 ******************************* */

    /**
     * 获取token与authstr
     * @param
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public JSONObject getToken(JSONObject object){
        HttpResponse resp = HttpRequest.post(getOrderSysTokenUrl)
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .body(object.toJSONString())
                .execute();
        String result = resp.body();

        String token = JSON.parseObject(result).getString("data");
        String tmpStr = authSalt.charAt(2) + authSalt.charAt(8) + token + authSalt.charAt(10) + authSalt.charAt(5);
        object.put("token", token);
        object.put("authStr", SecureUtil.md5(tmpStr));
        return object;
    }

    /**
     * 积分系统：转入钱包
     * @return
     */
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public String subPayToWallet(JSONObject object){
        HttpResponse resp = HttpRequest.post(subPayToWallet)
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .body(object.toJSONString())
                .execute();
        return resp.body();
    }

    /**
     * 发送订单通知
     * @param params 实例对象
     * @return
     */
    public JSONObject sendMsg(HashMap<String, Object> params){
        params.put("appid", msgAppid);
        params.put("wf_num", msgWfNum);
        HttpResponse resp = HttpRequest.post(bpmUrl)
                .header("sysid", sysId)
                .header("syspwd", sysPwd)
                .header("userId", "admin")
                .form(params)
                .execute();
        return JSON.parseObject(resp.body());
    }

}
